package controller;

import bean.Note;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.JsonObject;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import service.NoteService;

import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.time.LocalDateTime;

@WebServlet(urlPatterns = {"/notes", 
        "/notes/page",
        "/notes/search", 
        "/notes/detail", 
        "/notes/recent", 
        "/notes/create", 
        "/notes/update", 
        "/notes/delete"})
public class NoteController extends HttpServlet {

    private final NoteService noteService = new NoteService();
    private final Gson gson = new GsonBuilder()
            .registerTypeAdapter(LocalDateTime.class, (JsonSerializer<LocalDateTime>) (src, typeOfSrc, context) -> {
                if (src == null) return null;
                return new JsonPrimitive(src.toString().replace('T', ' '));
            })
            .create();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json;charset=UTF-8");
        String uri = req.getRequestURI();
        Integer userId = parseIntOrNull(req.getParameter("userId"));
        if (userId == null) userId = 1; // 简化：默认用户ID 1

        if (uri.endsWith("/notes")) {
            List<Note> list = noteService.listAll(userId);
            resp.getWriter().write(gson.toJson(list));
        } else if (uri.endsWith("/page")) {
            Integer pageSize = parseIntOrNull(req.getParameter("pageSize"));
            Integer page = parseIntOrNull(req.getParameter("page"));
            Integer categoryId = parseIntOrNull(req.getParameter("categoryId"));
            if (pageSize == null) pageSize = 20;
            if (page == null) page = 1;
            int offset = (page - 1) * pageSize;
            List<Note> items = noteService.listPaged(userId, categoryId, offset, pageSize);
            int total = noteService.countByFilter(userId, categoryId);
            int totalPages = (int) Math.ceil(total / (double) pageSize);
            JsonObject o = new JsonObject();
            o.add("items", gson.toJsonTree(items));
            o.addProperty("total", total);
            o.addProperty("page", page);
            o.addProperty("pageSize", pageSize);
            o.addProperty("totalPages", totalPages);
            resp.getWriter().write(gson.toJson(o));
        } else if (uri.endsWith("/search")) {
            String keyword = req.getParameter("keyword");
            Integer pageSize = parseIntOrNull(req.getParameter("pageSize"));
            Integer page = parseIntOrNull(req.getParameter("page"));
            Integer categoryId = parseIntOrNull(req.getParameter("categoryId"));
            if (pageSize == null) pageSize = 20;
            if (page == null) page = 1;
            int offset = (page - 1) * pageSize;
            List<Note> items = noteService.search(userId, keyword == null ? "" : keyword, categoryId, offset, pageSize);
            int total = noteService.countSearch(userId, keyword == null ? "" : keyword, categoryId);
            int totalPages = (int) Math.ceil(total / (double) pageSize);
            JsonObject o = new JsonObject();
            o.add("items", gson.toJsonTree(items));
            o.addProperty("total", total);
            o.addProperty("page", page);
            o.addProperty("pageSize", pageSize);
            o.addProperty("totalPages", totalPages);
            resp.getWriter().write(gson.toJson(o));
        } else if (uri.endsWith("/detail")) {
            Integer id = parseIntOrNull(req.getParameter("id"));
            Note note = id == null ? null : noteService.getById(id, userId);
            if (note == null) {
                resp.getWriter().write("{\"success\":false,\"error\":\"not_found\"}");
            } else {
                resp.getWriter().write(gson.toJson(note));
            }
        } else if (uri.endsWith("/recent")) {
            List<Note> list = noteService.recent7Days(userId);
            resp.getWriter().write(gson.toJson(list));
        } else {
            resp.getWriter().write("{\"success\":false,\"error\":\"unsupported_route\"}");
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json;charset=UTF-8");
        String uri = req.getRequestURI();
        Integer userId = parseIntOrNull(req.getParameter("userId"));
        if (userId == null) userId = 1;

        if (uri.endsWith("/create")) {
            Note n = new Note();
            n.setTitle(req.getParameter("title"));
            n.setContent(req.getParameter("content"));
            n.setUserId(userId);
            n.setCategoryId(parseIntOrNull(req.getParameter("categoryId")));
            int r = noteService.add(n);
            resp.getWriter().write(String.format(Locale.ROOT, "{\"success\":%s}", r > 0));
        } else if (uri.endsWith("/update")) {
            Note n = new Note();
            n.setId(parseIntOrNull(req.getParameter("id")));
            n.setTitle(req.getParameter("title"));
            n.setContent(req.getParameter("content"));
            n.setUserId(userId);
            n.setCategoryId(parseIntOrNull(req.getParameter("categoryId")));
            int r = noteService.update(n);
            resp.getWriter().write(String.format(Locale.ROOT, "{\"success\":%s}", r > 0));
        } else if (uri.endsWith("/delete")) {
            Integer id = parseIntOrNull(req.getParameter("id"));
            int r = id == null ? 0 : noteService.delete(id, userId);
            resp.getWriter().write(String.format(Locale.ROOT, "{\"success\":%s}", r > 0));
        } else {
            resp.getWriter().write("{\"success\":false,\"error\":\"unsupported_route\"}");
        }
    }

    private Integer parseIntOrNull(String v){
        try { return v == null || v.isBlank() ? null : Integer.valueOf(v); } catch(Exception ignored){ return null; }
    }
}